<template>
  <div class="dynamic-component-demo">
    <div class="demo-header">
      <h2>动态Vue组件渲染演示</h2>
      <p>将大模型返回的Vue组件代码动态渲染到页面上</p>
      <div class="mt-4 p-4 bg-blue-50 rounded-lg">
        <h3 class="text-lg font-semibold text-blue-800 mb-2">✨ 支持UnoCSS原子化CSS</h3>
        <p class="text-blue-700 text-sm">
          项目已集成UnoCSS，你可以在组件中直接使用原子化类名，如：
          <code class="bg-blue-100 px-1 rounded">flex-center</code>、 <code class="bg-blue-100 px-1 rounded">btn-primary</code>、
          <code class="bg-blue-100 px-1 rounded">card</code>、 <code class="bg-blue-100 px-1 rounded">text-primary</code> 等
        </p>
      </div>
    </div>

    <div class="demo-content">
      <!-- 左侧：代码编辑区 -->
      <div class="code-section">
        <h3>组件代码（大模型返回的内容）</h3>
        <textarea v-model="componentCode" class="code-editor" placeholder="在这里输入Vue组件代码..."></textarea>
        <div class="button-group">
          <button class="render-btn" @click="renderComponent">渲染组件</button>
          <button class="example-btn" @click="loadExample">加载示例</button>
          <button class="clear-btn" @click="clearCode">清空</button>
        </div>
      </div>

      <!-- 右侧：预览区 -->
      <div class="preview-section">
        <h3>组件预览</h3>
        <div class="preview-container">
          <!-- 错误信息显示 -->
          <div v-if="error" class="error-message">
            <h4>渲染错误：</h4>
            <pre>{{ error }}</pre>
          </div>

          <!-- 动态组件渲染区域 -->
          <div v-else-if="dynamicComponent" class="component-wrapper">
            <component :is="dynamicComponent" />
          </div>

          <!-- 默认提示 -->
          <div v-else class="empty-state">
            <p>在左侧输入组件代码，点击"渲染组件"按钮预览效果</p>
          </div>
        </div>
      </div>
    </div>

    <!-- 预设示例 -->
    <div class="examples-section">
      <h3>预设示例</h3>
      <div class="example-cards">
        <div v-for="(example, index) in examples" :key="index" class="example-card" @click="loadExampleCode(example.code)">
          <h4>{{ example.name }}</h4>
          <p>{{ example.description }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, shallowRef } from 'vue'
import * as Vue from 'vue'
import { titleCode, buttonCode, cardCode, unocssButtonCode, unocssCardCode, unocssFormCode } from './example-codes'

defineOptions({
  name: 'DynamicComponentDemo'
})

// 响应式数据
const componentCode = ref('')
const dynamicComponent = shallowRef(null)
const error = ref('')

// 预设示例
const examples = ref([
  {
    name: 'DK-Title组件',
    description: '标题组件示例',
    code: ''
  },
  {
    name: '按钮组件',
    description: '可点击的按钮组件',
    code: ''
  },
  {
    name: '卡片组件',
    description: '信息展示卡片',
    code: ''
  },
  {
    name: 'UnoCSS按钮组',
    description: '使用UnoCSS原子化类的按钮',
    code: ''
  },
  {
    name: 'UnoCSS卡片',
    description: '现代化的UnoCSS卡片组件',
    code: ''
  },
  {
    name: 'UnoCSS表单',
    description: '完整的用户注册表单',
    code: ''
  }
])

// 初始化示例代码
const initExamples = () => {
  examples.value[0].code = titleCode
  examples.value[1].code = buttonCode
  examples.value[2].code = cardCode
  examples.value[3].code = unocssButtonCode
  examples.value[4].code = unocssCardCode
  examples.value[5].code = unocssFormCode
}

// 渲染组件函数
const renderComponent = async () => {
  if (!componentCode.value.trim()) {
    error.value = '请输入组件代码'
    return
  }

  try {
    error.value = ''

    // 解析Vue单文件组件
    const component = await compileVueComponent(componentCode.value)
    dynamicComponent.value = component
  } catch (err) {
    console.error('组件渲染失败:', err)
    error.value = err instanceof Error ? err.message : '未知错误'
    dynamicComponent.value = null
  }
}

// 编译Vue组件的函数
const compileVueComponent = async (code: string) => {
  try {
    // 简单的SFC解析
    const templateMatch = code.match(/<template>([\s\S]*?)<\/template>/)
    const scriptMatch = code.match(/<script[^>]*>([\s\S]*?)<\/script>/)
    const styleMatch = code.match(/<style[^>]*>([\s\S]*?)<\/style>/)

    if (!templateMatch) {
      throw new Error('未找到template标签')
    }

    const template = templateMatch[1].trim()
    const script = scriptMatch ? scriptMatch[1].trim() : ''
    const style = styleMatch ? styleMatch[1].trim() : ''

    // 创建组件选项
    let componentOptions: any = {}

    if (script) {
      // 处理script内容，移除export default
      const scriptContent = script.replace(/export\s+default\s*/, '')

      // 如果script内容是一个对象字面量，直接解析
      if (scriptContent.trim().startsWith('{') && scriptContent.trim().endsWith('}')) {
        try {
          // 使用Function构造器安全地解析对象
          // eslint-disable-next-line no-new-func
          const func = new Function('return ' + scriptContent)
          componentOptions = func()
        } catch (e) {
          console.error('Script解析失败:', e)
          componentOptions = {}
        }
      } else {
        // 如果不是对象字面量，尝试用eval（不推荐，但为了兼容性）
        try {
          // eslint-disable-next-line no-eval
          componentOptions = eval('(' + scriptContent + ')')
        } catch (e) {
          console.error('Script执行失败:', e)
          componentOptions = {}
        }
      }
    }

    // 检查Vue编译器是否可用
    if (!Vue.compile) {
      throw new Error('Vue编译器不可用，请确保使用完整版Vue')
    }

    // 编译模板
    const render = Vue.compile(template)

    // 创建最终组件
    const componentId = `component-${Date.now()}`
    const finalComponent = {
      name: componentOptions.name || 'DynamicComponent',
      ...componentOptions,
      render,
      __scopeId: style ? `data-v-${componentId}` : undefined
    }

    // 如果有样式，动态添加到页面
    if (style) {
      const styleId = `dynamic-style-${componentId}`

      // 移除之前的样式
      const existingStyle = document.getElementById(styleId)
      if (existingStyle) {
        existingStyle.remove()
      }

      const styleElement = document.createElement('style')
      styleElement.id = styleId

      // 处理scoped样式
      let processedStyle = style
      if (finalComponent.__scopeId) {
        processedStyle = style.replace(/([^{}]+)\{/g, (match, selector) => {
          // 为每个选择器添加scope属性
          const selectors = selector
            .split(',')
            .map((s: string) => {
              const trimmed = s.trim()
              return `${trimmed}[${finalComponent.__scopeId}]`
            })
            .join(', ')
          return `${selectors} {`
        })
      }

      styleElement.textContent = processedStyle
      document.head.appendChild(styleElement)
    }

    return finalComponent
  } catch (err) {
    console.error('编译错误详情:', err)
    throw new Error(`组件编译失败: ${err instanceof Error ? err.message : String(err)}`)
  }
}

// 加载示例代码
const loadExample = () => {
  componentCode.value = examples.value[0].code
}

const loadExampleCode = (code: string) => {
  componentCode.value = code
}

// 清空代码
const clearCode = () => {
  componentCode.value = ''
  dynamicComponent.value = null
  error.value = ''
}

// 初始化
initExamples()
</script>

<style scoped>
.dynamic-component-demo {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}

.demo-header {
  text-align: center;
  margin-bottom: 30px;
}

.demo-header h2 {
  color: #303133;
  margin-bottom: 10px;
}

.demo-header p {
  color: #606266;
  font-size: 14px;
}

.demo-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-bottom: 40px;
}

.code-section {
  border: 1px solid #dcdfe6;
  border-radius: 8px;
  padding: 20px;
}

.code-section h3 {
  margin: 0 0 15px 0;
  color: #303133;
  font-size: 16px;
}

.code-editor {
  width: 100%;
  height: 400px;
  padding: 10px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  resize: vertical;
  margin-bottom: 15px;
}

.button-group {
  display: flex;
  gap: 10px;
}

.render-btn,
.example-btn,
.clear-btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s;
}

.render-btn {
  background-color: #409eff;
  color: white;
}

.render-btn:hover {
  background-color: #66b1ff;
}

.example-btn {
  background-color: #67c23a;
  color: white;
}

.example-btn:hover {
  background-color: #85ce61;
}

.clear-btn {
  background-color: #f56c6c;
  color: white;
}

.clear-btn:hover {
  background-color: #f78989;
}

.preview-section {
  border: 1px solid #dcdfe6;
  border-radius: 8px;
  padding: 20px;
}

.preview-section h3 {
  margin: 0 0 15px 0;
  color: #303133;
  font-size: 16px;
}

.preview-container {
  min-height: 400px;
  border: 2px dashed #dcdfe6;
  border-radius: 4px;
  padding: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.error-message {
  color: #f56c6c;
  text-align: left;
  width: 100%;
}

.error-message h4 {
  margin: 0 0 10px 0;
}

.error-message pre {
  background-color: #fef0f0;
  padding: 10px;
  border-radius: 4px;
  white-space: pre-wrap;
  word-break: break-word;
}

.component-wrapper {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.empty-state {
  color: #909399;
  text-align: center;
}

.examples-section h3 {
  color: #303133;
  margin-bottom: 15px;
}

.example-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 15px;
}

.example-card {
  border: 1px solid #dcdfe6;
  border-radius: 8px;
  padding: 15px;
  cursor: pointer;
  transition: all 0.3s;
}

.example-card:hover {
  border-color: #409eff;
  box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.2);
}

.example-card h4 {
  margin: 0 0 8px 0;
  color: #303133;
  font-size: 14px;
}

.example-card p {
  margin: 0;
  color: #606266;
  font-size: 12px;
}

@media (max-width: 768px) {
  .demo-content {
    grid-template-columns: 1fr;
  }
}
</style>
